home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) 1992 The Geometry Center; University of Minnesota
- 1300 South Second Street; Minneapolis, MN 55454, USA;
-
- This file is part of geomview/OOGL. geomview/OOGL is free software;
- you can redistribute it and/or modify it only under the terms given in
- the file COPYING, which you should have received along with this file.
- This and other related software may be obtained via anonymous ftp from
- geom.umn.edu; email: software@geom.umn.edu. */
-
- /* Authors: Charlie Gunn, Stuart Levy, Tamara Munzner, Mark Phillips */
-
- #include "mgP.h"
- #include "mgglP.h"
- #include "mgglshade.h"
- #include <gl/gl.h>
-
- #define MAXDEF 50
-
- /* materialno, lightmodelno, and lightno between 1 and 65535 are
- * legal. p 9-9 GL PROG GUIDE (munzner 9/17/91)
- */
- static int lightno = 1;
- static float kd = 1.0;
-
- mggl_appearance( struct mgastk *ma, int mask )
- {
- Appearance *ap = &(ma->ap);
-
- if (mask & APF_TRANSP) {
- if (ap->flag & APF_TRANSP) {
- zwritemask(0);
- blendfunction(BF_SA, BF_MSA);
- } else {
- zwritemask(~0);
- blendfunction(BF_ONE, BF_ZERO);
- }
- }
-
- if (mask & APF_LINEWIDTH) {
- linewidth(ap->linewidth);
- _mgc->has &= ~HAS_POINT;
- }
-
- if (mask & APF_SHADING) {
- if(!IS_SHADED(ap->shading) || ma->shader != NULL) {
- /* switch to constant shading by unbinding the lmodel */
- lmbind(LMODEL, 0);
- lmbind(MATERIAL, 0);
- _mgglc->d4f = c4f;
- _mgglc->lmcolor = LMC_COLOR;
- shademodel(IS_SMOOTH(ap->shading) ? GOURAUD : FLAT );
- ma->useshader = (ma->shader != NULL) && IS_SHADED(ap->shading);
- }
- else {
- /* turn shading on */
- shademodel( IS_SMOOTH(ap->shading) ? GOURAUD : FLAT );
- if (ap->lighting->valid)
- lmbind(LMODEL, ma->light_seq);
- lmbind(MATERIAL, ma->mat_seq);
- _mgglc->d4f = mggl_d4f;
- _mgglc->lmcolor = LMC_DIFFUSE;
- ma->useshader = 0;
- }
- }
-
- if(mask & APF_EVERT) {
- /*
- * Do automatic normal-flipping if requested.
- */
- _mgglc->n3f = (ap->flag & APF_EVERT) ?
- (void (*)())mggl_n3fevert : (void (*)())n3f;
- }
-
- /*
- * No GL calls are needed for the following attributes because
- * they are always interpreted at draw-time:
- * APF_FACEDRAW
- * APF_EDGEDRAW
- * APF_NORMSCALE
- */
-
- }
-
- /*-----------------------------------------------------------------------
- * Function: mggl_material
- * Description: bind a material. define it if it's not yet defined.
- * Args: *mat: Material to bind.
- * mask: Bitmask telling which material fields are valid.
- * Passed into mggl_materialdef.
- * Returns:
- * Author: munzner
- * Date: Wed Oct 16 16:06:47 1991
- * Notes: We must reset the "current GL color" after binding a
- * material.
- * We want color calls to change the *diffuse* color when
- * we're in shading mode. Thus we call lmcolor(LMC_DIFFUSE).
- * We also must keep track of the diffuse coefficient
- * for use in mggl_d[3,4]f, our wrapper for color calls.
- * C3f or c4f should never be called directly.
- * mg draw routines are responsible for establishing the
- * correct drawing color.
- */
- void
- mggl_material(register struct mgastk *astk, int mask)
- {
- float surface[MAXDEF];
- register float *f;
- Material *mat = &astk->mat;
- static float lmnull = LMNULL;
-
- mask &= mat->valid;
- if (mask & MTF_Kd)
- kd = mat->kd;
-
- if((mask & (MTF_EMISSION|MTF_DIFFUSE|MTF_AMBIENT|MTF_SPECULAR
- |MTF_SHININESS|MTF_Kd|MTF_Ka|MTF_Ks|MTF_ALPHA)) == 0)
- return; /* No GL changes to make. */
-
- if(astk->next && astk->next->mat_seq == astk->mat_seq) {
- /*
- * Fresh material needed. Erase any previous GL definition.
- * We'll need to load all valid fields to initialize it.
- */
- astk->mat_seq++;
- lmdef(DEFMATERIAL, astk->mat_seq, 0, &lmnull);
- lmbind(MATERIAL, astk->mat_seq);
- mask = mat->valid;
- }
-
- /* Build material definition */
- f = surface;
-
- if( mask & MTF_EMISSION) {
- *f++ = EMISSION;
- *f++ = mat->emission.r;
- *f++ = mat->emission.g;
- *f++ = mat->emission.b;
- }
-
- if( mask & (MTF_Ka | MTF_AMBIENT)) {
- *f++ = AMBIENT;
- *f++ = mat->ka * mat->ambient.r;
- *f++ = mat->ka * mat->ambient.g;
- *f++ = mat->ka * mat->ambient.b;
- }
- if( mask & (MTF_Kd | MTF_DIFFUSE)) {
- *f++ = DIFFUSE;
- *f++ = mat->kd * mat->diffuse.r;
- *f++ = mat->kd * mat->diffuse.g;
- *f++ = mat->kd * mat->diffuse.b;
- }
- if( mask & (MTF_Ks | MTF_SPECULAR | MTF_SHININESS)) {
- *f++ = SPECULAR;
- *f++ = mat->ks * mat->specular.r;
- *f++ = mat->ks * mat->specular.g;
- *f++ = mat->ks * mat->specular.b;
- *f++ = SHININESS;
- *f++ = mat->shininess;
- }
- if( mask & MTF_ALPHA) {
- *f++ = ALPHA;
- *f++ = mat->alpha;
- }
-
- *f = LMNULL;
-
- lmdef (DEFMATERIAL, astk->mat_seq, f - surface, surface);
- }
-
- void
- mggl_setshader(mgshadefunc shader)
- {
- register struct mgastk *ma = _mgc->astk;
- int wasusing = ma->useshader;
-
- ma->shader = shader;
- ma->useshader = (shader != NULL && IS_SHADED(ma->ap.shading));
- if(ma->useshader != wasusing)
- mggl_appearance(_mgc->astk, APF_SHADING);
- }
-
- void mggl_lighting(struct mgastk *astk, int mask)
- {
- LtLight *light;
- LmLighting *li = &astk->lighting;
-
- if (li->valid) {
- mggl_lightmodeldef( astk->light_seq, li, li->valid & mask );
- lmbind(LMODEL, astk->light_seq);
- }
-
- mmode(MVIEWING);
- pushmatrix();
- loadmatrix( _mgc->W2C );
- mggl_lights( li->lights, astk );
- popmatrix();
- }
-
- void
- mggl_lights( LtLight *light, struct mgastk *astk )
- {
- int i, lightsused;
- int baselight = -1;
-
- /* unbind all currently bound GL lights */
- for (i=0; i<MAXLIGHTS; ++i) {
- lmbind(LIGHT0+i, 0);
- }
-
- lightsused = 0;
- while (light) {
- if (light->Private == 0) {
- /* this is a new light */
- if(baselight < 0) {
- register struct mgastk *a;
- for(a = astk, baselight = 1; a != NULL; a = a->next)
- baselight += MAXLIGHTS; /* Count appearance stack depth */
- }
- light->Private = lightsused + baselight;
- light->changed = 1; /* set changed, to force lmdef below */
- }
-
- if( light->changed ) {
- mggl_lightdef( light->Private, light );
- light->changed = 0;
- }
- lmbind( LIGHT0+lightsused, light->Private );
- ++lightsused;
- light = light->next;
- }
- }
-
-
- int
- mggl_lightdef( int lightno, LtLight *light)
- {
- float lightsource[MAXDEF];
- float *f = lightsource;
-
- *f++ = AMBIENT;
- *f++ = light->ambient.r;
- *f++ = light->ambient.g;
- *f++ = light->ambient.b;
-
- *f++ = LCOLOR;
- *f++ = light->intensity * light->color.r;
- *f++ = light->intensity * light->color.g;
- *f++ = light->intensity * light->color.b;
-
- *f++ = POSITION;
- *f++ = light->globalposition.x;
- *f++ = light->globalposition.y;
- *f++ = light->globalposition.z;
- *f++ = light->globalposition.w;
-
- *f++ = LMNULL;
- lmdef( DEFLIGHT, lightno, f-lightsource, lightsource );
- return lightno;
- }
-
-
- int
- mggl_lightmodeldef(int lightmodel, LmLighting *lgt, int mask)
- {
- float light[40];
- float *f = light;
-
- if( mask & LMF_AMBIENT) {
- *f++ = AMBIENT;
- *f++ = lgt->ambient.r;
- *f++ = lgt->ambient.g;
- *f++ = lgt->ambient.b;
- }
-
- if( mask & LMF_LOCALVIEWER) {
- *f++ = LOCALVIEWER;
- *f++ = lgt->localviewer;
- }
-
- if( mask & (LMF_ATTENC | LMF_ATTENM)) {
- *f++ = ATTENUATION;
- *f++ = lgt->attenconst;
- *f++ = lgt->attenmult;
- }
- #ifdef don_t_do_this
- /* This causes trouble if the vertex order makes GL consider
- * our polygon to be backfacing -- then TWOSIDE causes it
- * to be mis-shaded from both sides..
- */
- if(_mgglc->cantwoside) {
- *f++ = TWOSIDE; /* Always enable TWOSIDE lighting if hardware */
- *f++ = 1.0; /* supports it. (is this a good idea?) */
- }
- #endif
-
- *f++ = LMNULL;
- lmdef (DEFLMODEL, lightmodel, f-light, light);
- return lightmodel;
- }
-
-
- /*-----------------------------------------------------------------------
- * Function: mggl_d4f
- * Description: wrapper for c4f
- * Args: c:
- * Returns:
- * Author: munzner
- * Date: Wed Sep 18 21:48:08 1991
- * Notes: We must multiply by kd (diffuse coefficient of the material)
- * since we called lmcolor(LMC_DIFFUSE) earlier in mggl_material
- * so we're overwriting the diffuse material with every
- * c4f call.
- */
- void
- mggl_d4f(c)
- float c[4];
- {
- float d[4];
- d[0] = c[0] * kd;
- d[1] = c[1] * kd;
- d[2] = c[2] * kd;
- d[3] = c[3];
- /* Let appearance alpha override object's alpha */
- if (_mgc->astk->mat.valid & MTF_ALPHA &&
- _mgc->astk->mat.override & MTF_ALPHA)
- d[3] = _mgc->astk->mat.alpha;
- c4f(d);
- }
-
-
- void
- mggl_n3fevert(register Point3 *n, register HPoint3 *p)
- {
- Point3 tn;
- register Point3 *cp;
-
- if(!(_mgc->has & HAS_CPOS))
- mg_findcam();
- cp = &_mgc->cpos;
- if( (p->x-cp->x) * n->x + (p->y-cp->y) * n->y + (p->z-cp->z) * n->z > 0) {
- tn.x = -n->x;
- tn.y = -n->y;
- tn.z = -n->z;
- n3f((float *)&tn);
- } else {
- n3f((float *)n);
- }
- }
-